package com.instpower.things.handlers;

import com.instpower.things.config.Configs;
import com.instpower.things.entity.Battery;
import com.instpower.things.entity.Cabinet;
import com.instpower.things.entity.ResponseMQ;
import com.instpower.things.helper.DateUtil;
import com.instpower.things.helper.Handler0902Util;
import com.instpower.things.helper.HexUtils;
import com.instpower.things.instpower.Connection;
import com.instpower.things.instpower.Handler;
import com.instpower.things.transport.DataBuffer;
import com.instpower.things.transport.MTData;
import com.instpower.things.transport.Request;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.instpower.things.config.Configs.CABINET_TIMEOUT;

/**
 * @ClassName Handler08F6Action
 * @Author: hellmash@gmail.com
 * @Date: 2020/4/2
 * @Version: 1.0.0
 * @Description: 主动上报状态信息
 */
@Component(value = "CMD08F6")
public class Handler08F6Action extends Handler<Request> {

    @Value("${things.timeZone}")
    private String zoneId;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public short getId() {
        return Configs.STATUS;
    }

    @Override
    public void execute(Connection connection, Request data) throws UnsupportedEncodingException {
        String sn = data.getHeader().getAddr();
        logger.info("[{}]:Exec - CMD08F6 - BEGIN",sn);
        MTData mtData = data.getData();
        byte[] bytes = mtData.getDatas();
        try {
            DataBuffer hbuffer = new DataBuffer();
            hbuffer.writeBytes(bytes);
//            String addr = buffer.readString(2);
//            byte[] res = buffer.readBytes(2);
//            byte bType = buffer.readByte();
//            short dlen = buffer.readShort();
//
//            byte[] odata = Hex.decodeHex(HexUtils.hexToString(buffer.readBytes(buffer.readableBytes())));
//            DataBuffer hbuffer = new DataBuffer(odata.length);
//            hbuffer.writeBytes(odata);
//            hbuffer.writeBytes(bytes);


            int orderNum = hbuffer.readInt();
            byte status = hbuffer.readByte();
            byte result = hbuffer.readByte();
            byte countNum = hbuffer.readByte();
            //设置机柜信息
            Cabinet cabinet = new Cabinet();
            cabinet.setSn(sn);
            cabinet.setOrderNo(Integer.toString(orderNum));
            cabinet.setOpResult((int) result);
            String now = DateUtil.formatNow(zoneId);
            cabinet.setLastUpdateTime(now);
            List<Battery> batteryList = new ArrayList<>();
            Map<String,String> batteryMap = new HashMap<>();

            String slotNumCacheKey = String.format(Configs.RENT_08F6_KEY_PREF,
                    data.getHeader().getAddr());
            String slotNumCache = redisTemplate.opsForValue().get(slotNumCacheKey);

            //删除临时缓存
            String finishKey = String.format(Configs.RENT_08F6_FINISH, cabinet.getOrderNo());
            //超过08F6发送的轮询间隔时间
            redisTemplate.opsForValue().set(finishKey, "1", 20, TimeUnit.SECONDS);

            //可借数量
            int rentNum = 0;
            int realRentNum = 0;
            //可还数量
            int returnNum = 0;
            for (byte i = 0; i < countNum; i++) {
                byte slotNum = hbuffer.readByte();
                byte runFlag = hbuffer.readByte();
                byte slotTag = hbuffer.readByte();
                //cid不为空表示有电池
                String bsn = hbuffer.readString(16);
                byte blevel = hbuffer.readByte();
                short chargeNum = hbuffer.readShort();
                byte bStatus = hbuffer.readByte();
                logger.info("08F6 ==>sn:{} ,bsn:{},slotNum:{},runFlag:{},slotTag:{},bStatus:{}",sn,bsn,slotNum,runFlag,slotTag,bStatus);
                if(null ==slotNumCache ){
                    logger.warn("no slot num cache in redis , key is {}",slotNumCacheKey);
                }
                if (null == bsn || bsn.trim().length() < 16) {
                    //槽位运行状态空闲0x00，状态标志正常0x00，去除0x00判断
                    returnNum += 1;
                    //判断当前槽位号是否是空的
                    if(null !=slotNumCache && slotNumCache.equals(Byte.toString(slotNum))){
                        redisTemplate.delete(slotNumCacheKey);
                    }
                } else {
                    //
                    if(null != slotNumCache && slotNumCache.equals(Byte.toString(slotNum))){
                        redisTemplate.delete(slotNumCacheKey);
                    }
                    Battery battery = new Battery();
                    battery.setCabinetSn(cabinet.getSn());
                    battery.setSn(bsn);
                    battery.setCycleCount(chargeNum);
                    battery.setFullFlag(bStatus);
                    battery.setFullPer(blevel);
                    battery.setRunFlag(runFlag);
                    if(judgeBatteryPower(battery.getFullPer())){
                        realRentNum ++;
                    };
                    battery.setSlotNum(slotNum);
                    battery.setSlotFlag(slotTag);
                    battery.setLastUpdateTime(now);
                    batteryList.add(battery);
                    batteryMap.put(battery.getSn(), mapper.writeValueAsString(battery));
                    //0000 0100,HEX 第三位为1表示可借
                    if ((slotTag & 4) == 4) {
                        rentNum += 1;
                    }
                    //检测redis租借中的订单集合内是否存在电池
                    checkRentingBatteryHash(cabinet.getSn(),bsn,slotNum);
                }
            }
            //机柜有电池，更新数据库和电池缓存
            if(batteryList.size() > 0) {
                instService.updateBatteryStatus(cabinet.getSn(),batteryList);
                redisTemplate.opsForHash().putAll(Configs.BATTERY_HASHKEY, batteryMap);
            }
            cabinet.setRentNum(rentNum);
            cabinet.setReturnNum(returnNum);
            cabinet.setBatteries(batteryList);
            cabinet.setLastUpdateTime(now);
            //电池柜状态3分钟内失效
            logger.info("[{}]:机柜信息同步到redis内:{}",cabinet.getSn(),mapper.writeValueAsString(cabinet));
            redisTemplate.opsForValue().set(cabinet.getSn(), mapper.writeValueAsString(cabinet));
            //更新机柜信息
            boolean isAvailable = true;
            if (status == 21 || status == 22){
                isAvailable = false;
            }
            instService.updateCabinetBeat(sn,isAvailable, realRentNum, returnNum);
        } catch (Exception dex) {
            logger.error("[{}]:机柜状态获取失败!",sn);
            logger.error(dex.getLocalizedMessage(),dex);
        }
        logger.info("[{}]:Exec - CMD08F6 - END",sn);
    }

    /**
     * 检测 renting_battery_hash内是否存在有租借中的订单
     * @param cabinetSn
     * @param batterySn
     * @param slotNum
     */
    public void checkRentingBatteryHash(String cabinetSn,String batterySn,int slotNum){
        if (batterySn == null){
            logger.info("[renting_battery_hash]:Cabinet:[{}],battery sn:{},slotNum:{}",cabinetSn,batterySn,slotNum);
            return;
        }
        String rentingBatteryHash = "renting_battery_hash";
        boolean isExist = redisTemplate.opsForHash().hasKey(rentingBatteryHash,batterySn);
        if (isExist){
            logger.info("cabinetSn:{} batterySn:{} is exist renting order",cabinetSn,batterySn);
            ResponseMQ mq = new ResponseMQ();
            mq.setCabinetSn(cabinetSn);
            mq.setSlotNum(slotNum);
            mq.setRequestType(1);
            mq.setOrderTime(DateUtil.formatNow(zoneId));
            mq.setBatterySn(batterySn);
            rabbitTemplate.convertAndSend("return_queue_key", mq);
        }
    }

    /**
     * 根据电池电量,判断电池是否属于可借状态
     * @param fullPer
     * @return
     */
    public boolean judgeBatteryPower(int fullPer) {
        boolean flag = false;
        String defaultBatteryPower = instService.querySystemData("system_default_battery_power");
        if(!StringUtils.isEmpty(defaultBatteryPower) ){
            if(fullPer >= Integer.parseInt(defaultBatteryPower)){
                flag = true;
            }
        }
        return flag;
    }

}
